home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
cuj1008.zip
/
RAMEY.ZIP
/
SUBLIST.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-14
|
11KB
|
414 lines
/*
Postman's Sort (R) Version 1.0
Copyright (c) Robert Ramey 1991. All Rights Reserved
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <links.h>
#include "psort.h"
#include "sublist.h"
#include "io.h"
#include "os.h"
#include "arg.h"
FILE *wfinptr = (FILE *)NULL; /* work file pointer for input*/
char *wfinbuf = NULL; /* and buffer for input */
int rb_size = RB_SIZE;
FILE *wfoutptr = (FILE *)NULL; /* work file pointer for output */
char *wfoutbuf = NULL; /* and buffer output */
int sb_size = SB_SIZE;
char wfname[DIR_NAME_SIZE + 9] = ""; /* name of work file */
FILE_SIZE next_disk;
STACK *s_stack;
private void
sublist_windup(void);
private void
sublist_write(int, SUBLIST *);
private RECORD *
sublist_read(SUBLIST *);
void *
get_space(STACK *, size_t);
void *
need(STACK *, size_t);
/*********************************************************************
sublist_init - get command line args associated with sublists
**********************************************************************/
void
sublist_init(argc, argv)
unsigned int argc;
char *argv[];
{
unsigned int i, l;
char *cptr;
rec_init(argc, argv);
/* default temporary directory */
cptr = getenv("TMP");
if(cptr != (char *)NULL){
strcpy(wfname, cptr);
strcat(wfname, FNDELIM);
}
i = arg_find(argc, argv, "-t");
if(i == -1)
i = arg_find(argc, argv, "-T");
if(i != -1){
argv[i++] = "";
if(i == argc
|| *argv[i] == '-'
|| *argv[i] == '\0'){
strcpy(wfname, "");
}
else{
/* save new name root for work file */
if(strlen(argv[i]) + 9 > DIR_NAME_SIZE)
error("Temporary directory name too long");
strcpy(wfname, argv[i]);
strcat(wfname, FNDELIM);
argv[i] = "";
}
}
i = arg_find(argc, argv, "-sb");
if(i != -1){
argv[i++] = "";
if(i >= argc
|| *argv[i] == '-'
|| *argv[i] == '0')
error("-sb switch must specify block size in K");
arg_value(argv[i], &sb_size);
if(sb_size > MAX_BUFFER_SIZE)
sb_size = MAX_BUFFER_SIZE;
argv[i] = "";
}
i = arg_find(argc, argv, "-rb");
if(i != -1){
argv[i++] = "";
if(i >= argc
|| *argv[i] == '-'
|| *argv[i] == '0')
error("-rb switch must specify block size in K");
arg_value(argv[i], &rb_size);
if(rb_size > MAX_BUFFER_SIZE)
rb_size = MAX_BUFFER_SIZE;
argv[i] = "";
}
/* setup for work file names */
strcat(wfname, "SXXXXXXX");
mktemp(wfname);
next_disk = 0L;
/* reserve memory for work file buffer before someone */
/* else takes it */
if(rb_size>0){
wfinbuf = malloc(rb_size * K);
if(!wfinbuf)
error("Couldn't get memory for workfile input buffer");
}
if(sb_size>0){
wfoutbuf = malloc(sb_size * K);
if(!wfoutbuf)
error("Couldn't get memory for workfile output buffer");
}
if(atexit(sublist_windup))
error("Couldn't register sublist_windup");
s_stack = stk_alloc();
return;
}
/*********************************************************************
sublist_allocate - get an array of sublists of the specified size.
If necessary write out other sublists to disk to make room in
main memory.
**********************************************************************/
SUBLIST *
sublist_allocate(n)
unsigned int n; /* number of sublists to be allocated */
{
register SUBLIST *sptr;
int i;
assert(stk_push(s_stack));
sptr = (SUBLIST *)get_space(s_stack, n * (SEG_SIZE)sizeof(SUBLIST));
/* initialize sublists_array */
sptr += n;
for(i = n; i--;){
--sptr;
sptr->size =
sptr->pcount =
sptr->count = 0;
sptr->disk = EOF;
sptr->memory = (RECORD *)NULL;
}
return sptr;
}
/*********************************************************************
sublist_fclose - close swap files.
**********************************************************************/
void
sublist_fclose(){
/* stack state of output file */
*(FILE_SIZE *)get_space(s_stack, sizeof(FILE_SIZE)) = next_disk;
/* if output has overflowed to stack */
if(wfoutptr){
fflush(wfoutptr); /* make sure all the data can be read */
if(!wfinptr){
wfinptr = fdopen(fileno(wfoutptr), "rb");
if(!wfinptr)
error("Couldn't open working file for reading");
if(rb_size != 0)
assert(!setvbuf(wfinptr, wfinbuf, _IOFBF, rb_size));
}
clearerr(wfinptr);
}
return;
}
/*********************************************************************
sublist_free - restore sublist stack to its state before last
allocate
**********************************************************************/
void
sublist_free(){
/* recover original state of output file */
next_disk = *((FILE_SIZE *)stk_end(s_stack) - 1);
/* throw away sublists */
assert(stk_pop(s_stack));
return;
}
/*********************************************************************
sublist_shrink - eliminate array of sublist headers from stack.
otherwise leave state of stack the same.
**********************************************************************/
void
sublist_shrink()
{
FILE_SIZE next_disk;
next_disk = *((FILE_SIZE *)stk_end(s_stack) - 1);
assert(stk_pop(s_stack));
assert(stk_push(s_stack));
*(FILE_SIZE *)get_space(s_stack, sizeof(FILE_SIZE)) = next_disk;
return;
}
/*********************************************************************
sublist_empty - write all sublists to disk upto amount to be emptied
**********************************************************************/
void
sublist_empty(blk_num, sublist, sublist_count)
int blk_num, sublist_count;
SUBLIST *sublist;
{
int j;
FILE_SIZE save_disk;
if(!wfoutptr){
wfoutptr = fopen(wfname, "w+b");
if(!wfoutptr)
error("Couldn't open work file for output");
if(sb_size != 0)
assert(!setvbuf(wfoutptr, wfoutbuf, _IOFBF, sb_size*K));
}
/*
save_disk = ftell(wfoutptr);
*/
assert(!fseek(wfoutptr, next_disk, SEEK_SET));
/* write sublists */
for(j = sublist_count; j-- > 0;)
sublist_write(blk_num, sublist + j);
next_disk = ftell(wfoutptr);
/*
assert(!fseek(wfoutptr, save_disk, SEEK_SET));
*/
return ;
}
/*********************************************************************
sublist_write - empty a sublist to disk as long as the block number
in the record is greater than or equal to the one specified
**********************************************************************/
private
void
sublist_write(blk_num, sublist)
int blk_num;
SUBLIST *sublist;
{
RECORD *record_address, *next_address;
size_t record_size;
FILE_SIZE file_address;
unsigned int i;
next_address = sublist->memory;
if(next_address == (RECORD *)NULL
|| blk_num > rec_frame(next_address))
return;
/* get disk address */
file_address = ftell(wfoutptr);
/* write link to previous record in this sublist */
efwrite(&(sublist->disk), sizeof(FILE_SIZE), 1, wfoutptr);
/* set up new disk pointer in sublist */
sublist->disk = file_address;
/* write all records in sublist to disk */
i = 0;
for(;;){
/* move to next member of chain */
record_address = next_address;
record_size = rec_size(record_address) + 1;
sublist->size += record_size + sizeof(ADDRESS);
++i;
/* check to see if this is the last record */
next_address = (RECORD *)nxtelem((ADDRESS)record_address, 0);
if(next_address == (RECORD *)NULL
|| blk_num > rec_frame(next_address)){
/* if it is mark it with a 1 */
rec_eob(record_address) = 1;
efwrite((void *)record_address, record_size, 1, wfoutptr);
break;
}
else{
rec_eob(record_address) = 0;
efwrite((void *)record_address, record_size, 1, wfoutptr);
}
}
/* update memory amounts */
sublist->memory = next_address;
sublist->pcount += i;
sublist->count -= i;
return;
}
/*********************************************************************
sublist_read - get a record from a sublist written to disk
**********************************************************************/
RECORD *
sublist_read(sublist)
SUBLIST *sublist;
{
static FILE_SIZE disk_address;
static int eob = 1;
RECORD *record_address;
size_t record_size;
/* if there are more records in the work file block */
if(eob){
/* get the next block */
assert(sublist);
disk_address = sublist->disk;
/* if nothing on disk */
if(disk_address == EOF){
/* we're done */
return (RECORD *)NULL;
}
/* otherwise update pointer to next block */
assert(-1L != fseek(wfinptr, disk_address, SEEK_SET));
efread(&(sublist->disk), sizeof(FILE_SIZE), 1, wfinptr);
}
/* get record size */
efread(&record_size, sizeof(record_size), 1, wfinptr);
/* get memory space for record, link, and terminating NULL */
record_address =
(RECORD *)need(d_stack, 1 + record_size + sizeof(ADDRESS));
/* build record in memory */
record_address = (RECORD *)mklinks(record_address, 1);
record_address->field[0] = record_size;
efread(
&record_address->field[1],
record_size - sizeof(int /*record_address->field[0]*/) + 1,
1,
wfinptr
);
eob = rec_eob(record_address);
rec_memflag(record_address) = FALSE;
/* and return its address */
return record_address;
}
/*********************************************************************
sublist_windup - close working file
**********************************************************************/
private
void
sublist_windup(){
if(wfinptr != (FILE *)NULL)
/* throw it away */
fclose(wfinptr);
if(wfoutptr != (FILE *)NULL){
/* throw it away */
fclose(wfoutptr);
remove(wfname);
}
}
/*********************************************************************
sublist_input - get next record from sublist
**********************************************************************/
RECORD *
sublist_input(sublist)
SUBLIST *sublist;
{
RECORD *record_address;
/* if there are records in memory */
record_address = sublist->memory;
if(record_address != (RECORD *)NULL){
/* adjust pointer to sublist in memory */
assert(sublist);
sublist->memory =
(RECORD *)nxtelem(record_address, 0);
/* and return the first record in the list */
return record_address;
}
else
return sublist_read(sublist);
}
/*********************************************************************
sublist_output - write records in a sublist i to standard output
**********************************************************************/
void
sublist_output(sublist, uflag)
SUBLIST *sublist; /* pointer to sublist to be written */
BOOLEAN uflag; /* flag to suppress duplicate records */
{
RECORD *record_address; /*temporary address */
BOOLEAN output_flag;
/* get next record from list */
output_flag = TRUE;
while(record_address = sublist_input(sublist)){
assert(record_address);
if(output_flag)
/* write record */
rec_output(record_address);
output_flag = !uflag;
}
}